package com.g0dkar.leet.persistence;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import ognl.OgnlException;
import br.com.caelum.vraptor.ioc.Component;

import com.g0dkar.leet.util.ognl.OgnlUtils;

/**
 * A Dummy Persistence Manager. It persists objects withing a static map.
 * 
 * @author Rafael M. Lins - g0dkar
 * 
 */
@Component
public class DummyPersistenceManager implements PersistenceManager {
	private static Map<Class<?>, List<Object>> objects;
	private static Long ID_VALUE;
	
	public static void init() {
		if (objects == null) {
			objects = new HashMap<Class<?>, List<Object>>();
			ID_VALUE = 1L;
		}
		if (ID_VALUE == null) {
			ID_VALUE = 1L;
		}
	}
	
	public void save(Serializable obj) throws Exception {
		init();
		
		List<Object> objs = objects.get(obj.getClass());
		
		if (objs == null) {
			objs = new ArrayList<Object>();
			objects.put(obj.getClass(), objs);
		}
		
		try {
			OgnlUtils.setWithException("id", ID_VALUE, obj);
		} catch (OgnlException e) {
			OgnlUtils.set("id" + obj.getClass().getSimpleName(), ID_VALUE, obj);
		}
		
		if (objs.add(obj)) {
			ID_VALUE++;
		}
	}
	
	public <T> T findById(Long id, Class<T> klass) throws Exception {
		init();
		
		List<Object> objs = objects.get(klass);
		
		if (objs != null && !objs.isEmpty()) {
			Long objID = null;
			for (Object object : objs) {
				objID = (Long) OgnlUtils.get("id", object);
				
				if (objID == null) {
					objID = (Long) OgnlUtils.get("id" + klass.getSimpleName(), object);
					
					if (objID == null) {
						continue;
					}
				}
				
				if (objID.equals(id)) {
					return (T) object;
				}
			}
		}
		
		return null;
	}
	
	public <T> Collection<T> findAll(Class<T> klass) throws Exception {
		init();
		
		return (Collection<T>) objects.get(klass);
	}
	
	public <T> Collection<T> findByParams(Map<String, Object> params, Class<T> klass) throws Exception {
		init();
		
		Collection<T> found = new ArrayList<T>();
		List<Object> objs = objects.get(klass);
		
		if (objs != null && objs.isEmpty()) {
			Object value;
			boolean equals;
			for (Object object : objs) {
				value = null;
				equals = true;
				
				for (Entry<String, Object> param : params.entrySet()) {
					value = OgnlUtils.get(param.getKey(), object);
					
					if ((value != null) && (param.getValue() != null)) {
						if (value.equals(param.getValue())) {
							continue;
						}
					}
				
					equals = false;
					break;
				}
				
				if (equals) {
					found.add((T) object);
				}
			}
		}
		
		return found.isEmpty() ? null : found;
	}

}
